// ------------------------------------------------------------------------------
// 
// Copyright (c) 2006-2008 Swampware, Inc.
// 
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// 
// ------------------------------------------------------------------------------
using System;

namespace wave
{
	/// <summary>
	/// Summary description for Program.
	/// </summary>
	class Program
	{

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main(string[] args)
		{
			System.Console.WriteLine("wave - Interactive Water Console");
			System.Console.WriteLine("Copyright (c) 2006-2008 Swampware, Inc.");
			System.Console.WriteLine("For more information visit http://www.swampware.com");
			System.Console.WriteLine("");

			System.AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
			System.AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
			Water.Output.Written += new Water.OutputEventHandler(Output_Written);

			System.Reflection.Assembly assembly = System.Reflection.Assembly.GetEntryAssembly();
			string location = assembly.Location;
			int index = location.LastIndexOf(System.IO.Path.DirectorySeparatorChar);
			string startup_path = location.Substring(0, index + 1);
			string script_path = startup_path + @"scripts" + System.IO.Path.DirectorySeparatorChar;

			while (true)
			{
				Water.Environment environment = new Water.Environment();
				Water.Evaluator evaluator = new Water.Reflection.ReflectionEvaluator();

				environment.Define("_Environment", environment);
				environment.Define("_Evaluator", evaluator);
				environment.Define("_StartupPath", startup_path);

//TODO this goes in the stack.
				Water.Dictionary frame = new Water.Dictionary();
				environment.Push("_Frame", frame);



				Water.Commands.LoadCommandCommand.LoadCommand(new Water.Commands.IncludeCommand(), environment);
				Water.Commands.LoadCommandCommand.LoadCommand(new Water.Commands.LoadBlockCommand(), environment);
				Water.Commands.LoadCommandCommand.LoadCommand(new Water.Commands.LoadCommand(), environment);
				Water.Commands.LoadCommandCommand.LoadCommand(new Water.Commands.LoadCommandCommand(), environment);
				Water.Commands.LoadCommandCommand.LoadCommand(new Water.Reflection.Commands.LoadMethodCommand(), environment);

				Water.Commands.LoadCommandCommand.LoadCommand(new wave.Commands.ExecCommand(), environment);
				Water.Commands.LoadCommandCommand.LoadCommand(new wave.Commands.ExitCommand(), environment);
				Water.Commands.LoadCommandCommand.LoadCommand(new wave.Commands.RestartCommand(), environment);
				Water.Commands.LoadCommandCommand.LoadCommand(new wave.Commands.SpawnCommand(), environment);

				//TODO DELETE
				Water.Commands.LoadCommandCommand.LoadCommand(new Water.Reflection.Commands.TypeofCommand(), environment);



				try
				{
					if (System.IO.File.Exists(script_path + "startup.water"))
					{
						Water.Commands.IncludeCommand.Include(script_path + "startup.water", environment, evaluator);
					}

					foreach (string arg in args)
					{
						// Run file.
						new Water.Interpreter(new Water.FileIterator(new Water.FileReader(arg), environment), environment, new wave.ConsoleEvaluator(evaluator, false)).Start();
					}
				}
				catch (System.Exception exception)
				{
					wave.ErrorPrinter.PrintError(exception, environment.CopyVariableStack("_Statement"));
				}


				// Run console.
				new Water.Interpreter(new wave.ConsoleIterator(environment), environment, new wave.ConsoleEvaluator(evaluator, true)).Start();



				if (environment.Peek("_Exit") != null)
				{
					break;
				}
				else if (environment.Peek("_Restart") != null)
				{
					System.Console.WriteLine("restarting...");
					System.Console.WriteLine("");
				}
				else
				{
					throw new System.Exception("UNKNOWN RESTART STATE.");
				}

				Water.Reflection.AssemblyCache.Clear();
			}
		}

		private static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
		{
			string name = args.Name;
			int index = name.IndexOf(",");
			if(index != -1)
			{
				name = name.Substring(0, index);
			}
			return Water.Reflection.AssemblyCache.LoadAssembly(name);
		}

		private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs args)
		{
			System.Exception exception = (System.Exception)args.ExceptionObject;
			System.Console.Write(exception.Message + "\n\n" + exception.StackTrace);
		}

		private static void Output_Written(object sender, Water.OutputEventArgs e)
		{
			System.Console.Write(e.Line);
		}

	}
}
